#pragma Once
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "log.hpp"
#include "Task.hpp"
#include "ThreadPool.hpp"

extern Log lg;
uint16_t defaultport = 8080;
std::string defaultip = "0.0.0.0";

enum
{
    SOCKET_ERR = 1,
    BIND_ERR,
    ListenError
};

class TcpServer
{
public:
    TcpServer(uint16_t port = defaultport, std::string ip = defaultip)
        : listensock_(-1), ip_(ip), port_(port)
    {
    }

    void Init()
    {
        listensock_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listensock_ < 0)
        {
            lg(Fatal, "create socket fail,listensock_ : %d ", listensock_);
            exit(SOCKET_ERR);
        }

        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(port_);
        server.sin_addr.s_addr = inet_addr(ip_.c_str());

        // bind 文件描述符
        socklen_t len = sizeof(server);
        if (bind(listensock_, (const struct sockaddr *)(&server), len) < 0)
        {
            lg(Fatal, "bind error, errno: %d, err string: %s", errno, strerror(errno));
            exit(BIND_ERR);
        }
        lg(Info, "bind success, errno: %d, err string: %s", errno, strerror(errno));

        // 连接
        //  Tcp是面向连接的，服务器一般是比较“被动的”，服务器一直处于一种，一直在等待连接到来的状态
        if (listen(listensock_, 10) < 0)
        {
            lg(Fatal, "listen error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(ListenError);
        }

        lg(Info, "listen socket success, listensock_: %d", listensock_);
    }

    void start()
    {
        // 创造线程池
        ThreadPool<Task>::GetInstance()->CreatThreads();
        while (true)
        {
            // 接受请求，提供新的sockfd
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(listensock_, (struct sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                lg(Warning, "accept error, errno: %d, errstring: %s", errno, strerror(errno)); //?
                // continue;
            }
            // 进行通信

            // char inbuff[1024];
            // int n = read(sockfd, inbuff, sizeof(inbuff));
            // if (n < 0)
            // {
            //     std::cout << "read fail" << std::endl;
            //     break;
            // }
            // inbuff[n] = 0;
            // std::cout << "client sat@ " << inbuff << std::endl;

            // std::string echo_string = "server return-->> ";
            // echo_string += inbuff;
            // n = write(sockfd, echo_string.c_str(), echo_string.size());
            // if (n < 0)
            // {
            //     std::cout << "write fail" << std::endl;
            //     break;
            // }

            // close(sockfd);

            // version 1 -- 单进程版
            // Service(sockfd, clientip, clientport);  
            // close(sockfd);

            // version 2 -- 多进程版
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     // child
            //     close(listensock_);
            //     if(fork() > 0) exit(0);
            //     Service(sockfd, clientip, clientport); //孙子进程， system 领养
            //     close(sockfd);
            //     exit(0);
            // }
            // close(sockfd);
            // // father
            // pid_t rid = waitpid(id, nullptr, 0);
            // (void)rid;

            // version 3 -- 多线程版本
            // ThreadData *td = new ThreadData(sockfd, clientip, clientport, this);
            // pthread_t tid;
            // pthread_create(&tid, nullptr, Routine, td);

            // version 4  -- 线程池版本 
            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32];
            inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));

            //创造任务并交给任务处理
            Task t(sockfd,clientip,clientport);
            ThreadPool<Task>::GetInstance()->Push(t);
        }
    }

    ~TcpServer()
    {
        // close(socketfd_);
    }

private:
    int listensock_;
    std::string ip_;
    uint16_t port_; // 表明服务器进程的端口号
};